﻿#include "VulkanTriangleWidget.h"
#include "Render/VulkanContext.h"
#include "Render/Widget/VulkanWindow.h"

CVulkanTriangleWidgets::~CVulkanTriangleWidgets()
{
    //销毁command buffer
    CVulkanContext::Get()->GetRecycleObjects()->CommandBuffers.Add(CommandBuffer);
}

void CVulkanTriangleWidgets::PreProcess(const TVector<SPreRenderTriangleWidget> &AllTriangleData)
{
    TVector<SPreRenderTriangleWidget> ValidData;
    for (const auto& TriangleData : AllTriangleData)
    {
        //检查数据是否合法
        if(TriangleData.Color.A==0)
        {
            continue;
        }

        if(TriangleData.Viewport.width<=0 || TriangleData.Viewport.height<=0)
        {
            continue;
        }

        //检查裁剪是否合法
        if(TriangleData.Scissor.extent.width<=0 || TriangleData.Scissor.extent.height<=0)
        {
            continue;
        }

        //如果裁剪矩形完全在视口外面，则不需要绘制
        if(TriangleData.Scissor.offset.x+TriangleData.Scissor.extent.width<=TriangleData.Viewport.x ||
            TriangleData.Scissor.offset.x>=TriangleData.Viewport.x+TriangleData.Viewport.width ||
            TriangleData.Scissor.offset.y+TriangleData.Scissor.extent.height<=TriangleData.Viewport.y ||
            TriangleData.Scissor.offset.y>=TriangleData.Viewport.y+TriangleData.Viewport.height)
        {
            continue;
        }


        ValidData.Add(TriangleData);
    }


    //创建渲染对象
    TriangleWidgets.Resize(ValidData.Num());
    for (int i = 0; i < ValidData.Num(); ++i)
    {
        TriangleWidgets[i].BindData(ValidData[i]);
    }

}

void CVulkanTriangleWidgets::CreateSelfRecordTasks(CVulkanWindow *InRenderSurface, SRenderCommandBuffers &OutCmdBuffersToExecute)
{
    if(TriangleWidgets.Num()==0)
    {
        return;
    }

    //创建command buffer
    if(!CommandBuffer)
    {
        //allocate a command buffer for this widget
        vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::eSecondary)
            .setCommandBufferCount(1);

        CommandBuffer = CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
    }


    OutCmdBuffersToExecute.ImageWidgetRenderPassCommandBuffers.Add(CommandBuffer);

    vk::CommandBufferInheritanceInfo CommandBufferInheritanceInfo=vk::CommandBufferInheritanceInfo()
        .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
        .setFramebuffer(InRenderSurface->GetCurrentFrameBuffer())
        .setSubpass(0)
    ;

    vk::CommandBufferBeginInfo CommandBufferBeginInfo=vk::CommandBufferBeginInfo()
        .setFlags(vk::CommandBufferUsageFlagBits::eRenderPassContinue)
        .setPInheritanceInfo(&CommandBufferInheritanceInfo);

    CommandBuffer.begin(CommandBufferBeginInfo);

    CommandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics,CVulkanContext::Get()->GetWidgetPipelines()->CanvasWidgetTrianglePipeline);
    for (auto& TriangleWidget : TriangleWidgets)
    {
        TriangleWidget.Draw(CommandBuffer);
    }

    CommandBuffer.end();



}

void CVulkanTriangleWidget::BindData(const SPreRenderTriangleWidget& Data)
{
    TriangleData=Data;
}

void CVulkanTriangleWidget::Draw(vk::CommandBuffer CommandBuffer)
{
    CommandBuffer.setViewport(0,1,&TriangleData.Viewport);
    CommandBuffer.setScissor(0,1,&TriangleData.Scissor);
                       
    SWidgetPipelines::STriangleItemVertexPushConstant TriangleItemVertexPushConstant;
    TriangleItemVertexPushConstant.Color[0]=TriangleData.Color.R;
    TriangleItemVertexPushConstant.Color[1]=TriangleData.Color.G;
    TriangleItemVertexPushConstant.Color[2]=TriangleData.Color.B;
    TriangleItemVertexPushConstant.Color[3]=TriangleData.Color.A;

    //convert Point from canvas widget space to NDC space
    TriangleItemVertexPushConstant.P0[0]=TriangleData.P0.X/ TriangleData.Viewport.width*2.0f-1.0f;
    TriangleItemVertexPushConstant.P0[1]=TriangleData.P0.Y/ TriangleData.Viewport.height*2.0f-1.0f;
    TriangleItemVertexPushConstant.P1[0]=TriangleData.P1.X/ TriangleData.Viewport.width*2.0f-1.0f;
    TriangleItemVertexPushConstant.P1[1]=TriangleData.P1.Y/ TriangleData.Viewport.height*2.0f-1.0f;
    TriangleItemVertexPushConstant.P2[0]=TriangleData.P2.X/ TriangleData.Viewport.width*2.0f-1.0f;
    TriangleItemVertexPushConstant.P2[1]=TriangleData.P2.Y/ TriangleData.Viewport.height*2.0f-1.0f;

    TriangleItemVertexPushConstant.ZOrder=TriangleData.Depth;

               
    CommandBuffer.pushConstants(
        CVulkanContext::Get()->GetWidgetPipelines()->CanvasWidgetTrianglePipelineLayout
        ,vk::ShaderStageFlagBits::eVertex
        ,0
        ,sizeof(SWidgetPipelines::STriangleItemVertexPushConstant)
        ,&TriangleItemVertexPushConstant);

    CommandBuffer.draw(3,1,0,0);
                    
}
